package org.moonlight.jvm.instructions.references.array;

import lombok.Getter;
import org.moonlight.jvm.instructions.base.BytecodeReader;
import org.moonlight.jvm.instructions.base.Instruction;
import org.moonlight.jvm.rtda.exclusive.Frame;
import org.moonlight.jvm.rtda.exclusive.OperandStack;
import org.moonlight.jvm.rtda.share.Object;
import org.moonlight.jvm.rtda.share.heap.Class;
import org.moonlight.jvm.rtda.share.heap.ClassLoader;

/**
 * new_array指令: 用来创建基本类型数组. 包括:
 *               boolean[], byte[], char[], short[], int[], float[], double[], long[]
 *               它需要两个操作数:
 *                 1. 一个uint8整数，在字节码中紧跟在指令操作码后面，表示要创建哪种类型的数组。
 *                     Java虚拟机规范把这个操作数叫作atype，并且规定了它的有效值 {@link ArrayType}
 *                 2. count，从操作数栈中弹出，表示数组长度
 *
 * @author Moonlight
 * @createTime 2023/9/13 13:57
 **/
public class NewArray implements Instruction {

    /** 在字节码中紧跟在指令操作码后面，表示要创建哪种类型的数组. 有效值 {@link ArrayType} **/
    @Getter
    private int aType;

    @Override
    public void fetchOperands(BytecodeReader reader) {
        this.aType = reader.readInt8();
    }

    @Override
    public void execute(Frame frame) {
        OperandStack stack = frame.getOperandStack();
        int count = stack.popInt();
        if (count < 0) {
            throw new NegativeArraySizeException();
        }
        ClassLoader loader = frame.getMethod().getClazz().getLoader();
        Class arrClass = getPrimitiveArrayClass(loader, this.aType);
        Object array = arrClass.newArray(count);
        stack.pushRef(array);
    }

    private Class getPrimitiveArrayClass(ClassLoader loader, int aType) {
        switch (aType) {
            case ArrayType.AT_BOOLEAN:
                return loader.loadClass("[Z");
            case ArrayType.AT_BYTE:
                return loader.loadClass("[B");
            case ArrayType.AT_CHAR:
                return loader.loadClass("[C");
            case ArrayType.AT_SHORT:
                return loader.loadClass("[S");
            case ArrayType.AT_INT:
                return loader.loadClass("[I");
            case ArrayType.AT_FLOAT:
                return loader.loadClass("[F");
            case ArrayType.AT_LONG:
                return loader.loadClass("[J");
            case ArrayType.AT_DOUBLE:
                return loader.loadClass("[D");
            default:
                throw new RuntimeException("非法的数组类型标识: " + aType);
        }
    }


}
